home *** CD-ROM | disk | FTP | other *** search
- /*
- * smupdate.c
- * 14 June 1993 by Mark C Smith • University of Michigan
- * Copyright (c) 1993 Mark C Smith
- *
- * uses "Essential Hack" code & methods to patch BeginUpdate and EndUpdate
- */
- #include <QuickDraw.h>
- #include <QDOffScreen.h>
- #include <Windows.h>
- #include <ToolUtils.h>
- #include <GestaltEqu.h>
- #include <Traps.h>
- #include "Useful.h"
- #include "smupdate.h"
-
- static Boolean besmooth;
- static GWorldPtr gwp = NULL;
- static PixMapHandle savepmh;
- static BitMap savebm;
- static Boolean inited = false;
- static StringHandle desktopsh;
-
- typedef pascal void BEUpdateRoutine( WindowPtr wp );
-
-
- /*
- * prototypes for our routines
- */
- pascal short SmUpdateGestalt( OSType selector,long *response );
- pascal void pBeginUpdate( WindowPtr wp, BEUpdateRoutine *oldBeginUpdateProc );
- pascal void pEndUpdate( WindowPtr wp );
-
- //
- // 14 June 1993 MCS: main was lifted (with appropriate mods) from Essential.c
- //
- // By convention from the essential hack loader, the init resource begins with the
- // four-byte gestalt selector for this hack, and an offset to the gestalt routine
- // to be installed on behalf of this hack. After that is a series of two-word
- // entries, where the first word specifies either a trap to be patched or a
- // low-memory vector to be patched. When the first word becomes zero, the traps
- // have ended.
-
- void main(void) {
- asm {
- dc.l sSmUpdate ; our gestalt selector.
- dc.w SmUpdateGestalt
-
- dc.w _BeginUpDate
- dc.w @_NewBeginUpdate
- dc.w _EndUpDate
- dc.w @_NewEndUpdate
- dc.w 0
-
- // OK, enough with the header. here's the patches. First, BeginUpdate. We
- // want to tail-patch BeginUpdate, so our patch inserts an extra parameter
- // (the old trap address) so our patch routine can do everything at a high
- // level. Note that this requires the trap routine (pBeginUpdate) to be
- // declared as a pascal routine, so that it automatically clears away
- // the extra parameter we added.
-
- _NewBeginUpdate:
- dc.l WayBadValue
- move.l (a7),-(a7) ; make space for an extra parameter.
- move.l @_NewBeginUpdate,4(a7) ; the old address is that parameter.
- bra pBeginUpdate ; go to high-level stuff.
-
- // Next is EndUpdate, which we need to head-patch. We set up a4, call the
- // high-level patch, and when it returns we go to the real routine. Note that
- // all the registers are saved, so high-level routine doesn't need to bother.
-
- _NewEndUpdate:
- dc.l WayBadValue
- movem.l d0/d1/d2/a0/a1/a4,-(a7) ; save registers
- lea main,a4
- move.l 28(a7), -(a7) ; pass WindowPtr that was original parameter
- bsr pEndUpdate ; call head patch
- movem.l (a7)+,d0/d1/d2/a0/a1/a4 ; restore regs.
- move.l @_NewEndUpdate,-(a7)
- rts ; go to original routine
- }
- }
-
- /*
- * 14 June 1993 MCS: the technique (and code) used in pBeginUpdate is lifted
- * with changes from Essential.c
- */
- pascal void
- pBeginUpdate( WindowPtr wp, BEUpdateRoutine *oldBeginUpdateProc )
- {
- long regs[6];
- GDHandle savedevice;
- CGrafPtr saveport;
- PixMapHandle pmh;
- Boolean iscgraf, isdesktop;
- Point pt;
- Rect r, boundsr;
- short i, depth;
- Str255 titleps;
- unsigned char *p;
- /*
- StringHandle sh;
- */
-
- asm { movem.l d0/d1/d2/a0/a1/a4,regs } /* save the registers */
- SetA4( &main ); /* set up access to our globals */
-
- // DebugStr( "\ppBeginUpdate calling (original) BeginUpdate" );
-
- oldBeginUpdateProc( wp ); /* call the real BeginUpdate */
-
- if ( !inited ) {
- desktopsh = GetString( 10250 ); /* XXX need to ensure that we get this from Finder */
- /* sh = GetString( STR_ONOFF ); */
- besmooth = true;
- inited = true;
- }
-
- if ( besmooth ) {
- GetWTitle( wp, titleps );
- isdesktop = false; /* optimistic */
-
- if ( desktopsh != NULL ) {
- LoadResource( (Handle)desktopsh );
- if ( titleps[ 0 ] == **desktopsh ) {
- p = *desktopsh + 1;
- for ( i = 1; i <= titleps[ 0 ]; ++i, ++p ) {
- if ( *p != titleps[ i ] ) {
- break;
- }
- }
- isdesktop = ( i > titleps[ 0 ] );
- }
- }
-
- if ( iscgraf = ((((CWindowPtr)wp)->portVersion & 0xC000 ) == 0xC000 )) {
- depth = 0; /* let NewGWorld figure out what depth to use */
- } else {
- depth = 1; /* force black and white */
- }
- }
-
- if ( besmooth && iscgraf && !isdesktop ) {
- GetGWorld( &saveport, &savedevice );
- SetPort( wp );
-
- /*
- * find bounds of window in global coords
- */
- boundsr = wp->portRect;
- pt.h = wp->portRect.left;
- pt.v = wp->portRect.top;
- LocalToGlobal( &pt );
- OffsetRect( &boundsr, pt.h, pt.v );
-
- /*
- * create offscreen GWorld using temporary memory if possible; otherwise fall
- * back to application memory
- */
- if ( NewGWorld( &gwp, depth, &boundsr, NULL, NULL, useTempMem ) == noErr ||
- NewGWorld( &gwp, depth, &boundsr, NULL, NULL, 0 ) == noErr ) {
- /*
- * erase offscreen pixmap and cram into window record
- */
- SetGWorld( gwp, NULL );
- EraseRect( &gwp->portRect );
- SetOrigin( wp->portRect.left, wp->portRect.top );
- pmh = GetGWorldPixMap( gwp );
- LockPixels( pmh );
- if ( iscgraf ) {
- savepmh = ((CWindowPtr)wp)->portPixMap;
- ((CWindowPtr)wp)->portPixMap = pmh;
- } else {
- // DebugStr( "\pb & w" );
- savebm = wp->portBits; /* struct copy */
- // wp->portBits.rowBytes = (*pmh)->rowBytes;
- // wp->portBits.bounds = (*pmh)->bounds;
- wp->portBits.baseAddr = GetPixBaseAddr( pmh );
- }
- } else {
- gwp = NULL;
- }
-
- SetGWorld( saveport, savedevice );
- }
-
- asm { movem.l regs,d0/d1/d2/a0/a1/a4 } /* restore the registers */
- }
-
-
- pascal void
- pEndUpdate( wp )
- WindowPtr wp;
- {
- GrafPtr saveport;
- PixMapHandle pmh;
- Boolean iscgraf;
-
- // DebugStr( "\ppEndUpdate" );
-
- if ( gwp != NULL ) {
- if ( iscgraf = ((((CWindowPtr)wp)->portVersion & 0xC000 ) == 0xC000 )) {
- ((CWindowPtr)wp)->portPixMap = savepmh;
- } else {
- // wp->portBits = savebm; /* struct copy */
- wp->portBits.baseAddr = savebm.baseAddr;
- }
- GetPort( &saveport );
- SetPort( wp );
- pmh = GetGWorldPixMap( gwp );
-
- /*
- * smooth update with our friend copybits
- */
- CopyBits( (BitMap *)*pmh, &wp->portBits, &gwp->portRect, &wp->portRect,
- srcCopy, iscgraf ? ((CGrafPtr)wp)->visRgn : wp->visRgn );
-
- /*
- * clean up the mess: dispose of GWorld and reset clip region and port
- */
- UnlockPixels( pmh );
- DisposeGWorld( gwp );
- gwp = NULL;
-
- SetPort( saveport );
- }
- }
-
-
- // 14 June 1993 MCS: The frame of the following routine was lifted from Essential.c
- //
- // This is the routine called by Gestalt to return the Proc Pointer.
- //
- // OSErr gestaltSelectorProc(OSType selector,long *response);
- //
- // Note that this is not the same tack taken by Scott & Alan! The idea
- // here is that rather than returning the address of a different routine
- // which returns other results, we have only this one routine and it
- // returns a multitude of different things, depending on the selector.
- // So, you call Gestalt with the 'sUpd' selector to get the address of this
- // routine, and then you call this routine with other selectors to get
- // (or do) other things.
-
- pascal short
- SmUpdateGestalt( OSType selector, long *response )
- {
- void *oldA4;
- long result;
- short err = noErr;
-
- oldA4 = SetA4( &main );
-
- switch( selector ) {
- case sSmUpdate:
- result = (long)&SmUpdateGestalt;
- break;
-
- case sSmOn: /* enable smooth updates */
- besmooth = true;
- break;
-
- case sSmOff: /* disable smooth updates */
- besmooth = false;
- break;
-
- case sSmStatus: /* return current setting */
- result = ( besmooth ? 1L : 0L );
- break;
-
- default:
- err = gestaltUnknownErr;
- }
-
- SetA4( oldA4 );
-
- if ( err == noErr ) {
- *response = result;
- }
-
- return( err );
- }
-